package com.beardedhen.harmonybootstrap;


import com.beardedhen.harmonybootstrap.api.attributes.BootstrapBrand;
import com.beardedhen.harmonybootstrap.api.attributes.ViewGroupPosition;
import com.beardedhen.harmonybootstrap.api.defaults.ButtonMode;
import com.beardedhen.harmonybootstrap.api.defaults.DefaultBootstrapBrand;
import com.beardedhen.harmonybootstrap.api.defaults.DefaultBootstrapSize;
import com.beardedhen.harmonybootstrap.api.view.*;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.app.Context;

import java.util.ArrayList;
import java.util.List;

import static com.beardedhen.harmonybootstrap.api.attributes.ViewGroupPosition.*;

/**
 * BootstrapButtonGroups are a LinearLayout which exclusively holds BootstrapButtons. It is possible
 * to set the properties of all children with one method call to this view. Options include
 * BootstrapBrand colors, roundable corners, 'outlineable' mode and different selection modes
 * e.g. Checkbox/Radio group.
 * If button mode is set to radio only one button is a button group may be selected at a time.
 */
public class BootstrapButtonGroup extends BootstrapGroup implements BootstrapSizeView,
        OutlineableView, RoundableView, BootstrapBrandView, ButtonModeView {

    private float bootstrapSize;
    private ButtonMode buttonMode;
    private BootstrapBrand bootstrapBrand;

    private boolean rounded;
    private boolean outline;

    private int checkedButtonId = 0;
    private static final String BOOTSTRAP_BUTTON_GROUP_BUTTON_MODE = "buttonMode";
    private static final String BOOTSTRAP_BUTTON_GROUP_SHOW_OUTLINE = "showOutline";
    private static final String BOOTSTRAP_BUTTON_GROUP_ROUNDED_CORNERS = "roundedCorners";
    private static final String BOOTSTRAP_BUTTON_GROUP_BOOTSTRAP_BRAND = "bootstrapBrand";
    private static final String BOOTSTRAP_BUTTON_GROUP_BOOTSTRAP_SIZE = "bootstrapSize";
    private static final String BOOTSTRAP_BUTTON_GROUP_CHECKED_BUTTON = "checkedButton";

    public BootstrapButtonGroup(Context context) {
        super(context);
        initialise(null);
    }

    public BootstrapButtonGroup(Context context, AttrSet attrs) {
        super(context, attrs);
        initialise(attrs);
    }

    public BootstrapButtonGroup(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialise(attrs);
    }

    private int getBrandOrdinal(String name) {
        int typeOrdinal = 7;
        if (name.equalsIgnoreCase("primary")) {
            typeOrdinal = 0;
        } else if (name.equalsIgnoreCase("success")) {
            typeOrdinal = 1;
        } else if (name.equalsIgnoreCase("info")) {
            typeOrdinal = 2;
        } else if (name.equalsIgnoreCase("warning")) {
            typeOrdinal = 3;
        } else if (name.equalsIgnoreCase("danger")) {
            typeOrdinal = 4;
        } else if (name.equalsIgnoreCase("regular")) {
            typeOrdinal = 5;
        } else if (name.equalsIgnoreCase("secondary")) {
            typeOrdinal = 6;
        }
        return typeOrdinal;
    }
    private int getButtonModeOrdinal(String name) {
        int typeOrdinal = 0;
        if (name.equalsIgnoreCase("regular")) {
            typeOrdinal = 0;
        } else if (name.equalsIgnoreCase("toggle")) {
            typeOrdinal = 1;
        } else if (name.equalsIgnoreCase("checkbox")) {
            typeOrdinal = 2;
        } else if (name.equalsIgnoreCase("radio")) {
            typeOrdinal = 3;
        }
        return typeOrdinal;
    }
    private int getSizeOrdinal(String name) {
        int typeOrdinal = 2;
        if (name.equalsIgnoreCase("XS")) {
            typeOrdinal = 0;
        } else if (name.equalsIgnoreCase("SM")) {
            typeOrdinal = 1;
        } else if (name.equalsIgnoreCase("MD")) {
            typeOrdinal = 2;
        } else if (name.equalsIgnoreCase("LG")) {
            typeOrdinal = 3;
        } else if (name.equalsIgnoreCase("XL")) {
            typeOrdinal = 4;
        }
        return typeOrdinal;
    }

    protected void initialise(AttrSet attrs) {
        if(attrs == null) {
            return;
        }

        try {
            this.rounded = attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_ROUNDED_CORNERS).isPresent() ?
                    attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_ROUNDED_CORNERS).get().getBoolValue() : false;
            this.outline = attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_SHOW_OUTLINE).isPresent() ?
                    attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_SHOW_OUTLINE).get().getBoolValue() : false;

            int typeOrdinal = attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_BUTTON_MODE).isPresent() ?
                    getButtonModeOrdinal(attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_BUTTON_MODE).get().getStringValue()) : -1;

            int brandOrdinal = attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_BOOTSTRAP_BRAND).isPresent() ?
                    getBrandOrdinal(attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_BOOTSTRAP_BRAND).get().getStringValue()) : -1;
            int sizeOrdinal = attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_BOOTSTRAP_SIZE).isPresent() ?
                    getSizeOrdinal(attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_BOOTSTRAP_SIZE).get().getStringValue()) : -1;
            this.checkedButtonId = attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_CHECKED_BUTTON).isPresent() ?
                    attrs.getAttr(BOOTSTRAP_BUTTON_GROUP_CHECKED_BUTTON).get().getIntegerValue() : 0;

            this.buttonMode = ButtonMode.fromAttributeValue(typeOrdinal);
            this.bootstrapBrand = DefaultBootstrapBrand.fromAttributeValue(brandOrdinal);
            this.bootstrapSize = DefaultBootstrapSize.fromAttributeValue(sizeOrdinal).scaleFactor();
        } catch (Exception e) {
            e.printStackTrace();
        }
        updateBootstrapGroup();
    }


    @Override
    protected void onBootstrapViewAdded() {
        updateBootstrapGroup();
    }

    @Override
    protected void onBootstrapViewRemoved() {
        updateBootstrapGroup();
    }

    protected void updateBootstrapGroup() {
        int childCount = getChildCount();
        int orientation = getOrientation();

        if (childCount == 0) {
            return;
        }
        else if (childCount == 1) {
            BootstrapButton button = retrieveButtonChild(0);
            button.setViewGroupPosition(SOLO, 0);
        }

        List<BootstrapButton> buttonList = new ArrayList<>();

        for (int i = 0; i < childCount; i++) {
            BootstrapButton button = retrieveButtonChild(i);

            if (button.getVisibility() == VISIBLE) {
                buttonList.add(button);
            }
        }

        final int size = buttonList.size();
        for (int i = 0; i < size; i++) {
            BootstrapButton button = buttonList.get(i);
            ViewGroupPosition position;

            if (i == 0) {
                position = orientation == HORIZONTAL ? START : TOP;
            }
            else if (i == size - 1) {
                position = orientation == HORIZONTAL ? END : BOTTOM;
            }
            else {
                position = orientation == HORIZONTAL ? MIDDLE_HORI : MIDDLE_VERT;
            }
            button.setViewGroupPosition(position, i);
            button.updateFromParent(bootstrapBrand, bootstrapSize, buttonMode, outline, rounded);
            if (buttonMode == ButtonMode.RADIO && button.isMustBeSelected()) {
                button.setSelected(true);
                onRadioToggle(i);
                checkedButtonId = 0;
            }
            else if (buttonMode == ButtonMode.RADIO && button.getId() == checkedButtonId) {
                button.setSelected(true);
                onRadioToggle(i);
            }
        }
    }

    private BootstrapButton retrieveButtonChild(int i) {
        Component view = getComponentAt(i);

        if ((view instanceof BootstrapButton)) {
            return (BootstrapButton) view;
        }
        else {
            throw new IllegalStateException("All child view of BootstrapButtonGroup must be BootstrapButtons");
        }
    }

    /**
     * Used for Radio Group Mode - resets all children to an unselected state,
     * apart from the calling Button.
     *
     * @param index the index of the button becoming selected
     */
    void onRadioToggle(int index) {
        for (int i = 0; i < getChildCount(); i++) {

            if (i != index) {
                BootstrapButton b = retrieveButtonChild(i);
                b.setSelected(false);
            }
        }
    }

    /*
     * Getters / Setters
     */

    public void check(int id) {
        this.checkedButtonId = id;
    }

    @Override public float getBootstrapSize() {
        return bootstrapSize;
    }

    @Override public void setBootstrapSize(DefaultBootstrapSize bootstrapSize) {
        setBootstrapSize(bootstrapSize.scaleFactor());
    }

    @Override public void setBootstrapSize(float bootstrapSize) {
        this.bootstrapSize = bootstrapSize;

        for (int i = 0; i < getChildCount(); i++) {
            BootstrapButton button = retrieveButtonChild(i);
            button.setBootstrapSize(this.bootstrapSize);
        }
    }

    public ButtonMode getButtonMode() {
        return buttonMode;
    }

    public void setButtonMode(ButtonMode buttonMode) {
        this.buttonMode = buttonMode;

        for (int i = 0; i < getChildCount(); i++) {
            BootstrapButton button = retrieveButtonChild(i);
            button.setButtonMode(buttonMode);
        }
    }

    @Override public void setBootstrapBrand(BootstrapBrand bootstrapBrand) {
        this.bootstrapBrand = bootstrapBrand;

        for (int i = 0; i < getChildCount(); i++) {
            BootstrapButton button = retrieveButtonChild(i);
            button.setBootstrapBrand(bootstrapBrand);
        }
    }

   @Override public BootstrapBrand getBootstrapBrand() {
        return bootstrapBrand;
    }

    @Override public void setShowOutline(boolean showOutline) {
        this.outline = showOutline;

        for (int i = 0; i < getChildCount(); i++) {
            BootstrapButton button = retrieveButtonChild(i);
            button.setShowOutline(outline);
        }
    }

    @Override public boolean isShowOutline() {
        return outline;
    }

    @Override public void setRounded(boolean rounded) {
        this.rounded = rounded;

        for (int i = 0; i < getChildCount(); i++) {
            BootstrapButton button = retrieveButtonChild(i);
            button.setRounded(rounded);
        }
    }

    @Override public boolean isRounded() {
        return rounded;
    }

}
